package projet_v1;

import java.util.List;

import projet_v1.simulation.Field;
import projet_v1.simulation.Location;

/**
 * Vampire class, derives from Character.
 * 
 * @author Antoine Lavail
 * 
 */
public class Vampire extends Character implements Actor {

	// Defaults HP.
	public static final int HP_VAMPIRES = 150;
	// Default speed.
	private static final int SPEED = 3;
	// Represents the number of day without being thirsty.
	private static int NB_MAX_DAYS_WITHOUT_BEING_THIRSTY = 4; // 8
	// True if the Vampire is thirsty.
	private boolean isThirsty;
	// Represents since how many days a Vampire is thirsty.
	private int daysThirsty;

	/**
	 * Constructor of class Vampire.
	 * 
	 * @param healthPoints
	 *            : the attributed health points.
	 */
	public Vampire(int healthPoints) {
		super(healthPoints, Breed.VAMPIRE);
		isThirsty = false;
		daysThirsty = 0;
	}

	/**
	 * Another constructor of class Vampire. Can put the vampire directly on the
	 * field, with a location.
	 * 
	 * @param healthPoints
	 *            : the attributed health points.
	 * @param f
	 *            : the current field.
	 * @param l
	 *            : the wanted location for the vampire.
	 */
	public Vampire(int healthPoints, Field f, Location l) {
		super(healthPoints, Breed.VAMPIRE, f, l, SPEED);
		isThirsty = false;
		daysThirsty = 0;
	}

	/**
	 * Another constructor of class Vampire. Can put the vampire directly on the
	 * field, with a location. And the breed too.
	 * 
	 * @param healthPoints
	 *            : the attributed health points.
	 * @param breed
	 *            : the wanted breed.
	 * @param f
	 *            : the current field.
	 * @param l
	 *            : the wanted location for the vampire.
	 */
	protected Vampire(int healthPoints, Breed breed, Field f, Location l) {
		super(healthPoints, breed, f, l, SPEED);
		isThirsty = false;
		daysThirsty = 0;
	}

	// Accessors and mutators

	public boolean getIsThirsty() {
		return isThirsty;
	}

	public void setIsThirsty(boolean isThirsty) {
		this.isThirsty = isThirsty;
	}

	public int getDaysThirsty() {
		return daysThirsty;
	}

	/**
	 * Method triggered on each character at the end of each turn.
	 */
	public void endOfTurn() {
		if (!isThirsty) {
			if ((daysThirsty >= NB_MAX_DAYS_WITHOUT_BEING_THIRSTY))
				isThirsty = true;
			else
				daysThirsty++;
		}
	}

	/**
	 * Method called when a vampire decides to bite a human
	 * 
	 * @param h
	 *            Human who gets bitten by this vampire
	 */
	public void bite(Human h) {
		if (h == null)
			throw new NullPointerException(
					"null human in the method bite of the class Vampire.");

		// The human has no way to escape. He gets bitten.
		h.setHasBeenBitten(true);
		// Vampire is not thirsty anymore
		isThirsty = false;
		daysThirsty = 0;
	}

	/**
	 * The attack of a vampire on someone else.
	 * 
	 * @param c
	 *            : the character attacked.
	 */
	protected void attack(Character c) {
		if (c == null)
			throw new NullPointerException(
					"null character in the method attack of the class Vampire.");
		if (isThirsty) {
			bite((Human) c);
		}
		c.reduceHealthPoints(5);
		c.lastAttackedBy = this.getBreed();
	}

	/**
	 * Make this character act ­ that is: make it do whatever it wants/needs to
	 * do.
	 * 
	 * @param currentField
	 *            The field currently occupied.
	 * @param updatedField
	 *            The field to transfer to.
	 * @param newActors
	 *            A list to add newly born character to.
	 */
	public void act(Field currentField, Field updatedField,
			List<Actor> newActors) {
		if (currentField == null)
			throw new NullPointerException(
					"null currentField passed in act method of human class.");
		if (updatedField == null)
			throw new NullPointerException(
					"null updatedField passed in act method of human class.");

		if (isAlive()) {
			List<Character> l = aroundCharacter(updatedField);
			for (Character character : l) {
				if (character.getBreed().equals(Breed.HUMAN)) {
					if ((!((Human) character).getHasBeenBitten())
							&& (character.isAlive())) {
						attack(character);
						break;
					}
				}
			}
			Location newLocation = updatedField.freeAdjacentLocation(
					getLocation(), SPEED);
			if (newLocation != null) {
				setLocation(newLocation);
				updatedField.place(this, newLocation);
			}
		}
	}

	/**
	 * When a vampire encounter someone else
	 * 
	 * @param c
	 *            : the encountered character.
	 */
	public void encounterCharacter(Character c) {
		if (c == null)
			throw new NullPointerException(
					"null character passed in encounterCharacter method of vampire class.");
		attack(c);
	}
}
